﻿/*!	r_render_obj_def_vertex.h
	@brief	レンダリングオブジェクト頂点定義
Copyright (c) 2010 Yuya Yamaguchi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef _R_RENDER_OBJ_DEF_VERTEX_H_
#define _R_RENDER_OBJ_DEF_VERTEX_H_

#include "../math/r_math_vector2.h"
#include "../math/r_math_vector3.h"
#include "../math/r_math_colorRGBi.h"
#include "../rtti/r_rtti_class_base.h"
#include "../util/r_util_singleton.h"
#include "../alloc/r_alloc_allocator.h"
#include "r_render_allocator.h"
#include <map>
#include <vector>

namespace r{
	namespace draw{
		class InputLayout;
		class ObjDefVertex;
		class VertexBuffer;
		class IndexBuffer;
		class VertexShader;
		class Context;
	}
}

namespace r{
	namespace render{
		//! 頂点情報
		union ObjDefVertexElementUse
		{
			ObjDefVertexElementUse( void )
			: useFlag( 0 )
			{
			}
			struct{
				r_ui32			useColor	:1;
				r_ui32			useUV		:1;
				r_ui32			useNormal	:1;
				r_ui32			useSkin4	:1;
			};
			r_ui32				useFlag;
			inline r_bool	operator == ( const ObjDefVertexElementUse& elm )const
			{
				return useFlag == elm.useFlag;
			}
			inline r_bool	operator != ( const ObjDefVertexElementUse& elm )const
			{
				return useFlag != elm.useFlag;
			}
			inline r_bool	operator < ( const ObjDefVertexElementUse& elm )const
			{
				return useFlag < elm.useFlag;
			}
			inline r_bool	operator <= ( const ObjDefVertexElementUse& elm )const
			{
				return useFlag <= elm.useFlag;
			}
			inline r_bool	operator > ( const ObjDefVertexElementUse& elm )const
			{
				return useFlag < elm.useFlag;
			}
			inline r_bool	operator >= ( const ObjDefVertexElementUse& elm )const
			{
				return useFlag >= elm.useFlag;
			}
		};
		typedef std::pair< ObjDefVertexElementUse, r::draw::InputLayout* >	ObjDefVertexElementUsePair;
		typedef std::map< ObjDefVertexElementUse, r::draw::InputLayout*, std::less< ObjDefVertexElementUse >, r::render::Allocator< ObjDefVertexElementUsePair > >		ObjDefVertexElementUseMap;

		// レンダリングオブジェクト用頂点定義
		/* 無駄データも含まれるけどデータパターンを簡略化するためにやむなし...
		*/

		//! 最小頂点定義
		struct ObjDefVertexPos
		{
			r::math::Vector3D		pos;
		};

		//! 頂点カラー
		struct ObjDefVertexColor
		{
			r::math::ColorRGBi		color0;
			r::math::ColorRGBi		color1;
		};

		//! UV
		struct ObjDefVertexUV
		{
			r::math::Vector2D		uv0;
			r::math::Vector2D		uv1;
		};

		//! 法線
		struct ObjDefVertexNormal
		{
			r::math::Vector3D		normal;
			r::math::Vector3D		tangent;
		};

		//! スキン情報
		struct ObjDefVertexSkin4
		{
			r_f32			weight[3];
			r_ui8			index[4];
		};

		//! サブエレメント情報
		struct ObjDefSubElement
		{
			//! 開始頂点インデックス
			r_ui32			fromIndex;
			//! 使用インデックス数
			r_ui32			useIndexCount;
		};
		typedef std::vector< ObjDefSubElement, r::render::Allocator< ObjDefSubElement > >		ObjDefSubElementArray;

		//! 頂点情報
		/*!
		*/
		class ObjDefVertex : public r::rtti::ClassBase
		{
			RRTTI_REFLECTION_DECLARE
		public:
			//! コンストラクタ
			/*!
			@param	[in]	vertexUseFlag
			*/
			ObjDefVertex( const ObjDefVertexElementUse& vertexUseFlag, r_ui32 vertexTotalCount, r_ui32 indexTotalCount, r_ui32 subelementTotalCount );
			//! デストラクタ
			virtual ~ObjDefVertex( void );
		public:
			//! 頂点情報をメモリにマップ
			r_bool			mapVertex( void );
			//! 頂点情報のマップを解除
			void			unmapVertex( void );

			//! 位置情報を設定
			void			setPosition( r_ui32 index, const r::math::Vector3D& pos );
			//! 法線情報を設定
			void			setNormal( r_ui32 index, const r::math::Vector3D& normal );
			//! タンジェント情報を設定
			void			setTangent( r_ui32 index, const r::math::Vector3D& tangent );
			//! 頂点カラー0を設定
			void			setColor0( r_ui32 index, const r::math::ColorRGBi& color );
			//! 頂点カラー1を設定
			void			setColor1( r_ui32 index, const r::math::ColorRGBi& color );
			//! UV0を設定する
			void			setUV0( r_ui32 index, const r::math::Vector2D& uv );
			//! UV1を設定する
			void			setUV1( r_ui32 index, const r::math::Vector2D& uv );
			//! スキン情報を設定する
			void			setSkin4( r_ui32 index, r_ui32 i0, r_ui32 i1, r_ui32 i2, r_ui32 i3, r_f32 w0, r_f32 w1, r_f32 w2 );

			//! インデックス情報をメモリにマップ
			r_bool			mapIndex( void );
			//! インデックス情報のマップを解除
			void			unmapIndex( void );
			//! インデックス情報を設定
			void			setIndex( r_ui32 index, r_ui32 num );
			//! 全ての頂点を一度に転送する
			void			setVertexAll( const void* allVertex );
			//! 全てのインデックスを一度に転送する
			void			setIndexAll( const r_ui16* allIndex );
			void			setIndexAll( const r_ui32* allIndex );

			//! サブエレメント情報を設定する
			void			setSubElementIndexInfo( r_ui32 from, r_ui32 count, r_ui32 index );
		public:
			//! 頂点情報を取得する
			ObjDefVertexElementUse	getVertexUseElement( void )const;
			//! 頂点数を取得する
			r_ui32							getVertexCount( void )const;
			//! インデックス数を取得する
			r_ui32							getIndexCount( void )const;
			//! サブエレメント数を取得する
			r_ui32							getSubElementCount( void )const;
			//! サブエレメントの開始頂点位置と頂点数を取得する
			r_bool							getSubElementIndexInfo( r_ui32& from, r_ui32& count, r_ui32 index )const;
	
			//! 頂点レイアウトを取得する
			const r::draw::InputLayout*		getInputLayout( void )const;
		public:
			//! サブエレメントの描画開始
			void							drawSubElementBegin( r::draw::Context* context );
			//! サブエレメントの描画を実行する
			void							drawSubElement( r::draw::Context* context, r_ui32 index );
			//! サブエレメントの描画終了
			void							drawSubElementEnd( r::draw::Context* context );
		protected:
		private:
			//! 頂点レイアウトリスト
			static ObjDefVertexElementUseMap*	layoutMapList;
			//! デフォルトの頂点シェーダ
			static r::draw::VertexShader*					defVS;
			//! 生成カウンタ
			static r_ui32								genCount;

			//! 頂点フラグ
			ObjDefVertexElementUse	useFlag;
			//! 頂点数
			r_ui32							vertexCount;
			//! インデックス数
			r_ui32							indexCount;
			//! 頂点レイアウト
			r::draw::InputLayout*			vertexLayout;
			//! 頂点情報
			r::draw::VertexBuffer*			vertexBuffer;
			//! インデックス情報
			r::draw::IndexBuffer*			indexBuffer;
			//! 1頂点ストライド
			r_ui32							strideSize;
			//! 頂点カラーオフセット
			r_ui32							colorOffset;
			//! 法線オフセット
			r_ui32							normalOffset;
			//! UVオフセット
			r_ui32							uvOffset;
			//! スキンオフセット
			r_ui32							skin4Offset;
			//! サブエレメント情報
			ObjDefSubElementArray	subelement;

		};
	}
}


#endif // _R_RENDER_OBJ_DEF_VERTEX_H_
